package othello.gui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import javax.swing.GroupLayout;
import javax.swing.GroupLayout.ParallelGroup;
import javax.swing.GroupLayout.SequentialGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import othello.players.HumanPlayer;
import othello.players.benchmarkplayers.Mobility;
import othello.players.benchmarkplayers.Positional;
import othello.players.benchmarkplayers.Random;
import othello.players.benchmarkplayers.HEUR;
import othello.players.benchmarkplayers.BENCH;
import othello.players.learnplayers.PosQ;
import othello.players.learnplayers.PosSarsa;
import othello.players.learnplayers.PosTD;
import othello.players.learnplayers.RandQ;
import othello.players.learnplayers.RandSarsa;
import othello.players.learnplayers.RandTD;
import othello.players.learnplayers.HeurQ;
import othello.players.learnplayers.HeurSarsa;
import othello.players.learnplayers.HeurTD;
import othello.players.learnplayers.BenchQ;
import othello.players.learnplayers.BenchSarsa;
import othello.players.learnplayers.BenchTD;
import othello.players.learnplayers.QLearning;
import othello.players.learnplayers.Sarsa;
import othello.players.learnplayers.TDPlayer;
import othello.players.learnplayers.AbstractNeuralNetworkPlayer.BenchmarkState;
import othello.util.GameDetails;

public class TrainingSettingsPanel extends JPanel {
	private static final long serialVersionUID = 1L;
	private final JLabel[] labels = {new JLabel("Trained player:"), new JLabel("Train against:"), new JLabel("Number of games:"), new JLabel("Learningrate (Neural Network):"), new JLabel("Load saved weights for training"), new JLabel("Save weights after training"), new JLabel("Use eligibility traces"), new JLabel("Play only, no training"), new JLabel("Games to learn before playing"), new JLabel("Games to play before learning"), new JLabel("Benchmark player (used when playing):"), new JLabel("Total number of runs"), new JLabel("First four play moves random"),};
    private final JComponent[] components = {new JComboBox(), new JComboBox(), new JComboBox(new String[]{"1", "100", "1000", "10000", "50000"}), new JTextField("0.01"), new JCheckBox(), new JCheckBox(), new JCheckBox(), new JCheckBox(), new JComboBox(new String[]{"1", "100", "1000", "10000", "50000"}), new JComboBox(new String[]{"472"}), new JComboBox(), new JComboBox(new String[]{"10"}), new JCheckBox(),};
    @SuppressWarnings("rawtypes")	// Because we use array of classes
	
	private final Class[] playerClasses = 
		{QLearning.class, Sarsa.class, TDPlayer.class, 
		 RandQ.class, RandSarsa.class, RandTD.class,
		 BenchQ.class, BenchSarsa.class, BenchTD.class,
		 HeurQ.class, HeurSarsa.class, HeurTD.class,
		 Random.class, HEUR.class, BENCH.class};
    
    public TrainingSettingsPanel(final SettingsObserver settingsObserver) {
        for (int j = 0; j < playerClasses.length; j++) {
            ((JComboBox) components[0]).addItem(playerClasses[j].getName());
            ((JComboBox) components[1]).addItem(playerClasses[j].getName());
            ((JComboBox) components[10]).addItem(playerClasses[j].getName());
        }
        ((JComboBox) components[2]).setSelectedItem("1000");
        ((JComboBox) components[8]).setSelectedItem("100");        
        ((JComboBox) components[11]).setSelectedItem("10");
        ((JComboBox) components[2]).setEditable(true);
        ((JComboBox) components[8]).setEditable(true);
        ((JComboBox) components[9]).setEditable(false);
        ((JComboBox) components[11]).setEditable(true);        
        ((JCheckBox) components[4]).setSelected(false);
        ((JCheckBox) components[5]).setSelected(true);
        ((JCheckBox) components[5]).setSelected(false);
        final GroupLayout layout = new GroupLayout(this);
        setLayout(layout);
        ParallelGroup pc1 = layout.createParallelGroup(GroupLayout.Alignment.LEADING);
        ParallelGroup pc2 = layout.createParallelGroup(GroupLayout.Alignment.LEADING);
        SequentialGroup sg1 = layout.createSequentialGroup();
        for (int i = 0; i < labels.length; i++) {
            pc1.addComponent(labels[i]);
            pc2.addComponent(components[i]);
            sg1.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE).addComponent(labels[i]).addComponent(components[i]));
        }
        final JButton saveButton = new JButton("Save");
        final JButton startButton = new JButton("Start training");
        startButton.setEnabled(false);
        final JComponent parentComponent = this;
        
        ((JCheckBox) components[7]).addItemListener(new ItemListener() {
			@Override
			public void itemStateChanged(ItemEvent itemEvent) {
				if (itemEvent.getStateChange() == 1) {
					components[3].setEnabled(false);
					components[5].setEnabled(false);
					components[8].setEnabled(false);
					components[9].setEnabled(false);
					components[10].setEnabled(false);
				} else {
					components[3].setEnabled(true);
					components[5].setEnabled(true);
					components[8].setEnabled(true);
					components[9].setEnabled(true);
					components[10].setEnabled(true);
				}
			}
        	
        });
        
        saveButton.addActionListener(new ActionListener() {
            @SuppressWarnings("unchecked")	// Because we use array of classes
			@Override
            public void actionPerformed(ActionEvent e) {
            	try {
            		BenchmarkState benchMarkState = ((JCheckBox)components[7]).isSelected() ? BenchmarkState.Playing : BenchmarkState.Training;
            		//~ BenchmarkState benchMarkState = ((JCheckBox)components[7]).isSelected() ? BenchmarkState.Playing : BenchmarkState.Benchmarking;
            		int totalRuns = Integer.parseInt((String) ((JComboBox) components[11]).getSelectedItem());
            		System.out.println("> debug: totalRuns = " + totalRuns);
            		Othello.setTrainingMoves(
						new GameDetails(
							playerClasses[((JComboBox) components[0]).getSelectedIndex()],
							playerClasses[((JComboBox) components[1]).getSelectedIndex()], 
							Integer.parseInt((String) ((JComboBox) components[2]).getSelectedItem()), 
							Double.parseDouble((String) ((JTextField) components[3]).getText()),
							((JCheckBox)components[4]).isSelected(),
							((JCheckBox)components[5]).isSelected(),
							((JCheckBox)components[6]).isSelected(),
							benchMarkState,
							Integer.parseInt((String) ((JComboBox) components[8]).getSelectedItem()),
							Integer.parseInt((String) ((JComboBox) components[9]).getSelectedItem()),
							playerClasses[((JComboBox) components[10]).getSelectedIndex()],
							0,
							((JCheckBox)components[12]).isSelected())
					);
					
            		for (int run = 0; run != totalRuns; ++run){						
						Othello.addS(
								new GameDetails(
										playerClasses[((JComboBox) components[0]).getSelectedIndex()],
										playerClasses[((JComboBox) components[1]).getSelectedIndex()], 
										Integer.parseInt((String) ((JComboBox) components[2]).getSelectedItem()), 
										Double.parseDouble((String) ((JTextField) components[3]).getText()),
										((JCheckBox)components[4]).isSelected(),
										((JCheckBox)components[5]).isSelected(),
										((JCheckBox)components[6]).isSelected(),
										benchMarkState,
										Integer.parseInt((String) ((JComboBox) components[8]).getSelectedItem()),
										Integer.parseInt((String) ((JComboBox) components[9]).getSelectedItem()),
										playerClasses[((JComboBox) components[10]).getSelectedIndex()],
										run,
										((JCheckBox)components[12]).isSelected())
						);											
					}
	                validate();
                        startButton.setEnabled(true);
            	} catch (NumberFormatException exception) {
                        JOptionPane.showMessageDialog(parentComponent, "Invalid values entered.", "Error", JOptionPane.ERROR_MESSAGE);
            	} 
            	
            }
        });
        
        startButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {				
				int totalRuns = Integer.parseInt((String) ((JComboBox) components[11]).getSelectedItem());
				for (int run = 0; run != totalRuns; ++run)					
					settingsObserver.startTraining();				
            }
        });
        
        pc1.addComponent(saveButton);
        pc2.addComponent(startButton);
        sg1.addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER).addComponent(saveButton).addComponent(startButton));
        layout.setAutoCreateGaps(true);
        layout.setAutoCreateContainerGaps(true);
        layout.setHorizontalGroup(layout.createSequentialGroup().addGroup(pc1).addGroup(pc2));
        layout.setVerticalGroup(sg1);
    }
}
